package com.liachen.stock.ext.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.liachen.common.constant.Constant;
import com.liachen.common.util.StockUtil;
import com.liachen.stock.entity.Notice;
import com.liachen.stock.entity.NoticeFile;
import com.liachen.stock.entity.Report;
import com.liachen.stock.entity.ZsStockInfo;
import com.liachen.stock.entity.ZsStockPool;
import com.liachen.stock.entity.etf.ZsEtfInfo;
import com.liachen.stock.ext.ZsxgService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/**
 * ZsxgServiceImpl
 *
 * @author d85v8h9 chen.liang
 * @date 2021/4/2 13:37
 * @since V1.0
 */
@Service
public class ZsxgServiceImpl implements ZsxgService {
    /**
     * 获取研报URL
     */
    private static final String GET_REPORT_URL = "https://www.zsxg.cn/api/v2/report/userReports?size=1000&pageNum=1";
    /**
     * 根据股票编码获取研报URL
     */
    private static final String GET_REPORT_BY_CODE_URL = "https://www.zsxg.cn/api/v2/report/list?code=";
    /**
     * 获取通知列表URL
     */
    private static final String GET_USER_NOTICES_URL = "https://www.zsxg.cn/api/v2/notice/userNoices";
    /**
     * 根据股票编码通知列表URL
     */
    private static final String GET_NOTICE_BY_CODE_URL = "https://www.zsxg.cn/api/v2/notice/listByCode?codes=";
    /**
     * 获取通知列表URL
     */
    private static final String GET_STOCK_URL = "https://www.zsxg.cn/api/v2/capital/info?code=%s&yearNum=6";

    /**
     * 获取股票池信息
     */
    private static final String GET_STOCK_POOL_URL = "https://www.zsxg.cn/api/v2/userSelectStrategy/info/";

    /**
     * 获取ETF信息
     */
    private static final String GET_ETF_URL = "http://zsxg.cn/api/v2/capital/info?code=%s";
    /**
     * 获取交易所交易基金短暂url
     */
    private static final String GET_ETF_BRIEF_URL = "http://zsxg.cn/api/v2/index/list?type=%s";

    /**
     * 获取历史PE
     */
    private static final String GET_STOCK_PE_URL = "https://stock.cheesefortune.com/api/v3/details/pepb?code=%s&type=pe&years=10Y&tryHard=true";

    /**
     * 获取净利润
     */
    private static final String GET_STOCK_NET_PROFIT_URL = "https://stock.cheesefortune.com/api/v3/details/growAbility?code=%s&dataType=single&type=2&years=2";
    private static final String GET_STOCK_CONFIG_URL = "https://stock.cheesefortune.com/api/v3/data/getByconfig?dataCacheId=%d&codes=%s";

    @Override
    public List<Report> getReportList() throws IOException {
        Document doc = Jsoup.connect(GET_REPORT_URL).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return result.getJSONArray("datas").toList(Report.class);
        }
        return Lists.newArrayList();
    }

    @Override
    public List<Report> getReportListByCode(String code) throws IOException {
        Document doc = Jsoup.connect(GET_REPORT_BY_CODE_URL + code).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return result.getJSONArray("datas").toList(Report.class);
        }
        return Lists.newArrayList();
    }

    @Override
    public List<Notice> getNoticeList() throws IOException {
        Document doc = Jsoup.connect(GET_USER_NOTICES_URL).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return result.getJSONArray("datas").toList(Notice.class);
        }
        return Lists.newArrayList();
    }

    @Override
    public List<Notice> getNoticeListByCode(String code) throws IOException {
        Document doc = Jsoup.connect(GET_NOTICE_BY_CODE_URL + code).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return result.getJSONArray("datas").toList(Notice.class);
        }
        return Lists.newArrayList();
    }

    @Override
    public List<NoticeFile> getNoticeUrlList(int id) throws IOException {
        Document doc = Jsoup.connect("https://www.zsxg.cn/api/v2/notice/listFileById?id=" + id).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return result.getJSONArray("datas").toList(NoticeFile.class);
        }
        return Lists.newArrayList();
    }

    @Override
    public ZsStockInfo getStockInfo(String stockCode) throws IOException {
        Document doc = Jsoup.connect(String.format(GET_STOCK_URL, stockCode)).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return JSONUtil.toBean(result.getStr("datas"), ZsStockInfo.class);
        }
        return null;
    }

    @Override
    public ZsStockPool getStockFromPool(String poolId) throws IOException {
        Document doc = Jsoup.connect(GET_STOCK_POOL_URL + poolId).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return JSONUtil.toBean(result.getStr("datas"), ZsStockPool.class);
        }
        return null;
    }

    @Override
    public ZsEtfInfo getEtfInfo(String etfCode) throws IOException {
        Document doc = Jsoup.connect(String.format(GET_ETF_URL, etfCode)).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        if (Objects.equals(result.getStr("code"), "000")) {
            return JSONUtil.toBean(result.getStr("datas"), ZsEtfInfo.class);
        }
        return null;
    }

    @Override
    public List<ZsEtfBriefInfo> getBriefInfo(List<String> types) throws IOException {
        List<ZsEtfBriefInfo> zsEtfBriefInfoList = Lists.newArrayList();
        for(String type : types) {
            Document doc = Jsoup.connect(String.format(GET_ETF_BRIEF_URL, type)).ignoreContentType(true).header("token", Constant.ZSXG_TOKEN).userAgent(Constant.USER_AGENT).get();
            JSONObject result = JSONUtil.parseObj(doc.text());
            if (Objects.equals(result.getStr("code"), "000")) {
                zsEtfBriefInfoList.addAll(JSONUtil.toList(result.getJSONArray("datas"), ZsEtfBriefInfo.class));
            }
        }
        return zsEtfBriefInfoList;
    }

    @Override
    public JSONObject getPE(String code, String name) throws IOException {
        String filePath = String.format("%s\\%s\\%s.txt", StockUtil.getStockBasePath(), "市盈率", name);
        if(FileUtil.exist(filePath)) {
            return JSONUtil.readJSONObject(new File(filePath), Charset.forName(Constant.UTF_8));
        }
        Document doc = Jsoup.connect(String.format(GET_STOCK_PE_URL, code)).ignoreContentType(true).headers(this.getDefaultHeaders()).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        FileUtil.writeString(result.toStringPretty(), filePath, Constant.UTF_8);

        return result;
    }

    @Override
    public JSONObject getNetProfit(String code, String name) throws IOException {
        String filePath = String.format("%s\\%s\\%s.txt", StockUtil.getStockBasePath(), "净利润", name);
        if(FileUtil.exist(filePath)) {
            return JSONUtil.readJSONObject(new File(filePath), Charset.forName(Constant.UTF_8));
        }
        Document doc = Jsoup.connect(String.format(GET_STOCK_NET_PROFIT_URL, code)).ignoreContentType(true).headers(this.getDefaultHeaders()).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());

        FileUtil.writeString(result.toStringPretty(), filePath, Constant.UTF_8);
        return result;
    }

    @Override
    public JSONObject getConfig(Integer dataCacheId, String code, String name) throws IOException {
        String filePath = String.format("%s\\%s\\%s.txt", StockUtil.getStockBasePath(), "基础信息", name);
        if(FileUtil.exist(filePath)) {
            return JSONUtil.readJSONObject(new File(filePath), Charset.forName(Constant.UTF_8));
        }
        Document doc = Jsoup.connect(String.format(GET_STOCK_CONFIG_URL, dataCacheId, code)).ignoreContentType(true).headers(this.getDefaultHeaders()).userAgent(Constant.USER_AGENT).get();
        JSONObject result = JSONUtil.parseObj(doc.text());
        FileUtil.writeString(result.toStringPretty(), filePath, Constant.UTF_8);
        return result;
    }

    private Map<String, String> getDefaultHeaders() {
        Map<String, String> defaultHeaders = Maps.newHashMapWithExpectedSize(3);
        defaultHeaders.put("zstokv1", "31b33102087da6e1c2fec245094cdb4c");
        defaultHeaders.put("timeStamp", "1717975186471");
        return defaultHeaders;
    }
}
